home *** CD-ROM | disk | FTP | other *** search
- /*--------------------------------------------------------------------------------
- Copyright ©1993 Steve Israelson
- All rights reserved.
-
- Permisson granted for personal use only.
- --------------------------------------------------------------------------------*/
- #include <FixMath.h>
- #include <Menus.h>
- #include <Events.h>
- #include <Resources.h>
- #include <stdarg.h>
- #include "debug.h"
- #include "Brain.h"
- #include "terminator.proto.h"
-
- extern int vsprintf(char *sbuffer, char *fmt, va_list arg);
-
- #define MyMenuID 1000
-
- #define MIN_SPEED 10
-
- #define NICE_LAND (1 << ROAD | 1 << FOREST | 1 << GRASS)
- #define WATER (1 << RIVER | 1 << SWAMP | 1 << CRATER)
- #define OBSTACLE (1 << BUILDING | 1 << RUBBLE | 1 << HALFBUILDING)
- #define LAND (NICE_LAND | WATER | OBSTACLE)
- #define UNITS (1 << BOAT | 1 << REFBASE_T | 1 << PILLBOX_T)
-
- #define clearkey(CONTROLVECTOR, COMMAND) CONTROLVECTOR &= ~(1<<COMMAND)
-
- #define MAX_MSGS 16
- #define MIN_WAIT (60 * 2)
- #define PILL_MSG 0
- #define BASE_MSG 1
- #define MOVE_MSG 2
-
-
- long thinkStart; /* start time for thinking */
- long lastMsg, /* the last time a message was displayed */
- lastObstructed; /* the last time we were obstructed */
- BrainInfo *brainInfo; /* the info packet */
- MenuHandle MyMenu; /* the options menu */
- Boolean aggressive; /* menu option */
- Boolean laymines; /* menu option */
- Boolean clearmines; /* menu option */
- Boolean placepills; /* menu option */
- u_long newKeys, newTaps, /* new keys to press or tap */
- lastKeys, lastTaps; /* last keys we pressed or tapped */
- short repeatLastKeys; /* should we repeat the last key? if so how many times */
- long msgTimes[MAX_MSGS]; /* timers for the different msg types */
- ObjectInfo *closestShot; /* the closest shot to us */
- short incoming_shells; /* how many incomming shells */
- WORLD_X lastSeenPillx; /* last pillbox we have seen */
- WORLD_Y lastSeenPilly;
- WORLD_X basesx[16]; /* array of all the bases we have seen */
- WORLD_Y basesy[16];
-
- // For Mac fixed point trig routines, full circle is 2 * PI * 0x10000
- // We want full circle to be 0x100, so divide by (2 * PI * 0x10000 / 0x100)
- // which is 1608 in decimal
- /* assume us at 0,0 return angle to x,y (in fixed) */
- #define aim(X,Y) ((FixATan2(-(Y),(X))/1608) & 0xFF)
-
- // sin and cos routines are adjusted to take angles in the range 0-255
- // and return return values in the range +/-128
- #define sin(X) ((short)(FracSin((u_char)(X)*1608L) >> 23))
- #define cos(X) ((short)(FracCos((u_char)(X)*1608L) >> 23))
-
- #define rangeFromMe(OB) findrange((OB)->x, (OB)->y, brainInfo->tankx, brainInfo->tanky)
-
-
- /*--------------------------------------------------------------------------------
- The main brain killing machaine
- --------------------------------------------------------------------------------*/
- pascal short main(BrainInfo *theInfo)
- {
- if (theInfo->InfoVersion != CURRENT_BRAININFO_VERSION)
- return -1;
-
- brainInfo = theInfo;
- thinkStart = TickCount();
-
- switch (brainInfo->operation)
- {
- case BRAIN_OPEN:
- if (openBrain())
- return 0;
- closeBrain();
- return -1;
- break;
- case BRAIN_CLOSE:
- closeBrain();
- return 0;
- break;
- case BRAIN_THINK:
- think();
- return 0;
- break;
- case MyMenuID:
- return(doMenu(brainInfo->menu_item));
- break;
- default:
- return 0;
- break;
- }
- }
-
- /*--------------------------------------------------------------------------------
- Init all our globals. Set up menus.
- --------------------------------------------------------------------------------*/
- Boolean openBrain(void)
- {
- short x;
-
- aggressive = laymines = clearmines = placepills = true;
- lastKeys = lastTaps = lastObstructed = 0;
- repeatLastKeys = 0;
- lastSeenPilly = lastSeenPillx = 0;
- for (x = 0; x < 16; ++x)
- basesx[x] = basesy[x] = 0;
- lastMsg = TickCount();
-
- InsertMenu(MyMenu = GetMenu(MyMenuID), 0);
- DrawMenuBar();
- CheckItem(MyMenu, 1, aggressive);
- CheckItem(MyMenu, 2, laymines);
- CheckItem(MyMenu, 3, clearmines);
- CheckItem(MyMenu, 4, placepills);
-
- for (x = 0; x < MAX_MSGS; ++x)
- msgTimes[x] = 0;
-
- return true;
- }
-
- /*--------------------------------------------------------------------------------
- Trash our menus.
- --------------------------------------------------------------------------------*/
- void closeBrain(void)
- {
- DeleteMenu(MyMenuID);
- ReleaseResource((Handle)MyMenu);
- DrawMenuBar();
- }
-
- /*--------------------------------------------------------------------------------
- Do a menu, maybe someday actually do something here.
- --------------------------------------------------------------------------------*/
- short doMenu(short item)
- {
- switch (item)
- {
- case 1:
- CheckItem(MyMenu, 1, aggressive ^= 1);
- break;
- case 2:
- CheckItem(MyMenu, 2, laymines ^= 1);
- break;
- case 3:
- CheckItem(MyMenu, 3, clearmines ^= 1);
- break;
- case 4:
- CheckItem(MyMenu, 4, placepills ^= 1);
- break;
- default:
- return -1;
- }
- return 0;
- }
-
- /*--------------------------------------------------------------------------------
- I think, therfore I kill. Do man actions, then move actions, then others.
- --------------------------------------------------------------------------------*/
- void think(void)
- {
- newKeys = 0;
- newTaps = 0;
-
- countIncommingShots();
-
- if (!doMan()) /* place pills, lay mines */
- doMove();
- doOther();
-
- *(brainInfo->holdkeys) = newKeys;
- *(brainInfo->tapkeys) = newTaps;
- lastKeys = newKeys;
- lastTaps = newTaps;
- }
-
- /*--------------------------------------------------------------------------------
- Move our tank, sitting still is useless unless we are refuling.
- You should rank these according the priority you think these are.
- --------------------------------------------------------------------------------*/
- Boolean doMove(void)
- {
- if (avoidDeepWater())
- return true;
- if (avoidMines())
- return true;
- if (checkObstructions())
- return true;
- if (avoidShots())
- return true;
- if (avoidPill())
- return true;
- if (avoidEnemy())
- return true;
- if (getMan())
- return true;
- if (avoidWater())
- return true;
- if (approachEnemyPill())
- return true;
- if (approachBase())
- return true;
- if (approachEnemyBase())
- return true;
-
- selectRoute();
-
- /* if nothing to do then speed up! Places to go etc.. */
- speedUp();
- return false;
- }
-
- /*--------------------------------------------------------------------------------
- Refuel if we are low. Capture nearby neutral bases.
- --------------------------------------------------------------------------------*/
- Boolean approachBase(void)
- {
- long range;
- ObjectInfo *ob;
- short x, closestBase = -1;
- long minDistance = 0x7fffffff;
- Boolean found;
-
- if (!brainInfo->base) /* no base nearby so look for some farther away */
- {
- for (ob = &brainInfo->objects[0]; ob < &brainInfo->objects[brainInfo->num_objects]; ob++)
- {
- if (ob->info & OBJECT_HOSTILE)
- continue;
- if (ob->object == OBJECT_REFBASE && ob->info & OBJECT_NEUTRAL)
- {
- range = rangeFromMe(ob);
- if ((range >> 8) < 14)
- {
- if (nearestEnemyPill(ob->x, ob->y)) /* should check distance here ##### */
- continue;
- /*sendDebugMsg(BASE_MSG, "B%d,%d", (int)(ob->x >> 8), (int)(ob->y >> 8));*/
- approachSpace(ob->x, ob->y);
- return speedUp();
- }
- }
- if (!brainInfo->carriedpills && brainInfo->armour > 7
- && brainInfo->shells > 20 && brainInfo->mines > 10)
- continue;
- }
-
- /* no acceptable base nearby, so if we need it, lets find one we have been to before */
- if (brainInfo->armour < 4)
- {
- for (x = 0; x < 16; ++x)
- {
- if (basesx[x] || basesy[x])
- {
- range = findrange(basesx[x], basesy[x], brainInfo->tankx, brainInfo->tanky);
- if (range < minDistance)
- {
- minDistance = range;
- closestBase = x;
- }
- }
- }
- if (closestBase != -1)
- {
- /* sendDebugMsg(BASE_MSG, "Seek RB %d,%d",basesx[closestBase] >> 8,basesy[closestBase] >> 8); */
- approachSpace(basesx[closestBase], basesy[closestBase]);
- speedUp();
- return true;
- }
- }
- return false;
- }
-
- /* nearby hostile base, ignore -- later maybee we should kill it */
- if (brainInfo->base->info & OBJECT_HOSTILE)
- return false;
-
- /* are we on a base, if so sit still */
- if (terrainSpot() == REFBASE_T)
- {
- found = false;
- for (x = 0; x < 16; ++x)
- {
- if (basesx[x] || basesy[x])
- continue;
- if ((basesx[x] >> 8) == (brainInfo->tankx >> 8)
- && (basesy[x] >> 8) == (brainInfo->tanky >> 8))
- {
- found = true;
- break;
- }
- }
- if (!found) /* add to our database */
- for (x = 0; x < 16; ++x)
- {
- if (basesx[x] || basesy[x])
- continue;
- basesx[x] = brainInfo->tankx;
- basesy[x] = brainInfo->tanky;
- /* sendDebugMsg(BASE_MSG, "RBS %d,%d", brainInfo->tankx >> 8, brainInfo->tanky >> 8); */
- break;
- }
-
- slowDown();
- /* stay on the base until fueled */
-
- if (brainInfo->base_armour > MIN_BASE_ARMOUR && brainInfo->armour != 8)
- return true;
- if (brainInfo->base_shells && brainInfo->shells != 40)
- return true;
- if (brainInfo->base_mines && brainInfo->mines != 40)
- return true;
-
- /* lets get going, places to go things to kill */
- speedUp();
- return false;
- }
-
- /* approach the nearby base, unless there is an enemy pill nearby */
- if (!(brainInfo->base->info & OBJECT_NEUTRAL)
- && !(brainInfo->carriedpills && brainInfo->man_status == 0)
- && brainInfo->armour > 7
- && brainInfo->shells > 20 && brainInfo->mines > 10)
- return false;
-
- if (brainInfo->base_armour <= MIN_BASE_ARMOUR || brainInfo->base_shells == 0
- || brainInfo->base_mines == 0)
- return false;
-
- if (nearestEnemyPill(brainInfo->base->x, brainInfo->base->y)) /* should check distance here ##### */
- return false;
-
- /*sendDebugMsg(BASE_MSG, "CB%d,%d", (int)(brainInfo->base->x >> 8), (int)(brainInfo->base->y >> 8));*/
- approachSpace(brainInfo->base->x, brainInfo->base->y);
- range = rangeFromMe(brainInfo->base);
- if ((range >> 8) < 2 && brainInfo->speed > MIN_SPEED)
- slowDown();
- else
- speedUp();
- return true;
- }
-
- /*--------------------------------------------------------------------------------
- Add code here to destroy!
- --------------------------------------------------------------------------------*/
- Boolean approachEnemyBase(void)
- {
- }
-
- /*--------------------------------------------------------------------------------
- Are we stuck? then get unstuck and get going, busy busy busy.
- --------------------------------------------------------------------------------*/
- Boolean checkObstructions(void)
- {
- TERRAIN nearSpace;
- short x, y;
- Boolean tryNewApproach = false; /* try something else cause were still stuck */
-
- if (lastObstructed || brainInfo->tankobstructed)
- {
- sendDebugMsg(MOVE_MSG, "stk");
- speedUp();
- x = brainInfo->tankx >> 8;
- y = brainInfo->tanky >> 8;
-
- if (!lastObstructed)
- lastObstructed = TickCount() + 60;
- else if (lastObstructed < TickCount())
- lastObstructed = 0;
- if (lastObstructed && lastObstructed < TickCount() + 20)
- tryNewApproach = true;
- nearSpace = raw_getmapcell(x - 1, y) & TERRAIN_MASK;
- if (nearSpace != BUILDING && nearSpace != HALFBUILDING && nearSpace != DEEPSEA)
- {
- if (!tryNewApproach)
- {
- approachSpace((x - 1) << 8, y << 8);
- return speedUp();
- }
- tryNewApproach = false;
- }
- nearSpace = raw_getmapcell(x + 1, y) & TERRAIN_MASK;
- if (nearSpace != BUILDING && nearSpace != HALFBUILDING && nearSpace != DEEPSEA)
- {
- if (!tryNewApproach)
- {
- approachSpace((x + 1) << 8, (y) << 8);
- return speedUp();
- }
- tryNewApproach = false;
- }
- nearSpace = raw_getmapcell(x, y - 1) & TERRAIN_MASK;
- if (nearSpace != BUILDING && nearSpace != HALFBUILDING && nearSpace != DEEPSEA)
- {
- if (!tryNewApproach)
- {
- approachSpace((x) << 8, (y - 1) << 8);
- return speedUp();
- }
- tryNewApproach = false;
- }
- nearSpace = raw_getmapcell(x, y + 1) & TERRAIN_MASK;
- if (nearSpace != BUILDING && nearSpace != HALFBUILDING && nearSpace != DEEPSEA)
- {
- if (!tryNewApproach)
- {
- approachSpace((x) << 8, (y + 1) << 8);
- return speedUp();
- }
- tryNewApproach = false;
- }
-
- sendDebugMsg(MOVE_MSG, "fire");
- if (!approachObject(TERRAIN_MASK, BUILDING, 1, 128))
- approachObject(TERRAIN_MASK, HALFBUILDING, 1, 128);
- setkey(newTaps, KEY_shoot);
- return true;
- }
- return false;
- }
-
- /*--------------------------------------------------------------------------------
- Select the best route to travel. Randomly turn for variety.
- --------------------------------------------------------------------------------*/
- Boolean selectRoute(void)
- {
- u_char x, y;
-
- if (repeatLastKeys)
- {
- newKeys = lastKeys;
- --repeatLastKeys;
- return true;
- }
- if (rnd(0, 100) < 98)
- {
- /* if it is close, then why turn */
- if (findObject(TERRAIN_MASK, ROAD, 1, 64, &x, &y))
- return false;
- if (findObject(TERRAIN_MASK, FOREST, 1, 64, &x, &y))
- return false;
- if (findObject(TERRAIN_MASK, GRASS, 1, 64, &x, &y))
- return false;
-
- /* if it is not close, but near, then turn */
- if (approachObject(TERRAIN_MASK, ROAD, 4, 30))
- return true;
- if (approachObject(TERRAIN_MASK, FOREST, 4, 30))
- return true;
- if (approachObject(TERRAIN_MASK, GRASS, 4, 30))
- return true;
- if (approachObject(TERRAIN_MASK, ROAD, 14, 30))
- return true;
- if (approachObject(TERRAIN_MASK, FOREST, 14, 30))
- return true;
- if (approachObject(TERRAIN_MASK, GRASS, 14, 30))
- return true;
- }
-
- if (rnd(0, 100) < 50)
- setkey(newKeys, KEY_turnleft);
- else
- setkey(newKeys, KEY_turnright);
- repeatLastKeys = 5;
- }
-
- /*--------------------------------------------------------------------------------
- Approach an enemy pill and decimate it.
- --------------------------------------------------------------------------------*/
- Boolean approachEnemyPill(void)
- {
- ObjectInfo *ob;
- u_long range;
- short direction;
- short da;
-
- if (brainInfo->shells < 8)
- return false;
- for (ob = &brainInfo->objects[0]; ob < &brainInfo->objects[brainInfo->num_objects]; ob++)
- {
- if (ob->object == OBJECT_PILLBOX && (ob->info & OBJECT_HOSTILE))
- {
- if (brainInfo->armour <= 4 && ob->direction > 1) /* wimp out only if damaged */
- continue;
-
- range = rangeFromMe(ob);
- approachSpace(ob->x, ob->y);
- if ((range >> 8) >= 7)
- {
- /*sendDebugMsg(PILL_MSG, "P%d,%d", (int)(ob->x >> 8), (int)(ob->y >> 8));*/
- speedUp();
- }
- else
- if (ob->direction < 2)
- {
- /*sendDebugMsg(PILL_MSG, "P%d,%d", (int)(ob->x >> 8), (int)(ob->y >> 8));*/
- speedUp();
- }
- else
- slowDown();
-
- if (ob->direction && range >> 8 <= 7) /* if not dead then kill! */
- {
- direction = aim((unsigned long)ob->x - (unsigned long)brainInfo->tankx,
- (unsigned long)ob->y - (unsigned long)brainInfo->tanky);
- da = brainInfo->direction - direction;
- if (da < 4 && da > -4)
- setkey(newTaps, KEY_shoot);
- }
- lastSeenPillx = ob->x;
- lastSeenPilly = ob->y;
- /*sendDebugMsg(PILL_MSG, "PS%d,%d", (int)(lastSeenPillx >> 8), (int)(lastSeenPilly >> 8));*/
- return true;
- }
- }
- if (brainInfo->armour > 4 && (lastSeenPilly || lastSeenPillx))
- {
- /*sendDebugMsg(PILL_MSG, "PS%d,%d", (int)(lastSeenPillx >> 8), (int)(lastSeenPilly >> 8));*/
- approachSpace(lastSeenPillx, lastSeenPilly);
- if (findrange(brainInfo->tankx, brainInfo->tanky, lastSeenPillx, lastSeenPilly) >> 8 < 15)
- lastSeenPillx = lastSeenPilly = 0;
- speedUp();
- return true;
- }
- return false;
- }
-
- /*--------------------------------------------------------------------------------
- Return the nearest enemy pill.
- --------------------------------------------------------------------------------*/
- ObjectInfo *nearestEnemyPill(WORLD_X x, WORLD_Y y)
- {
- ObjectInfo *ob, *closestPill;
- u_long range, closest;
- short direction;
- short da;
-
- closestPill = nil;
- closest = 8 << 8; /* must be close enough to shoot */
- for (ob = &brainInfo->objects[0]; ob < &brainInfo->objects[brainInfo->num_objects]; ob++)
- {
- if (ob->object == OBJECT_PILLBOX && (ob->info & OBJECT_HOSTILE))
- {
- range = findrange(ob->x, ob->y, x, y);
- if (range < closest)
- {
- closest = range;
- closestPill = ob;
- }
- }
- }
- return closestPill;
- }
-
- /*--------------------------------------------------------------------------------
- Shoot at hostiles and walls and clear mines, farm build recover man etc.
- --------------------------------------------------------------------------------*/
- Boolean doOther(void)
- {
- doMan();
- }
-
- /*--------------------------------------------------------------------------------
- If the man is far away then wait for him.
- If he is very far away, then go get him.
- --------------------------------------------------------------------------------*/
- Boolean getMan(void)
- {
- short dx, dy;
- long distance;
-
- if (brainInfo->man_status > 1) /* outside tank and alive, for now */
- {
- dx = (brainInfo->tankx >> 8) - (brainInfo->man_x >> 8);
- dy = (brainInfo->tanky >> 8) - (brainInfo->man_y >> 8);
- distance = dx * dx + dy * dy;
- if (brainInfo->manobstructed == 2 || distance > 100) /* go get him */
- {
- approachSpace(brainInfo->man_x, brainInfo->man_y);
- return speedUp();
- }
- if (distance > 25)
- return slowDown();
- }
- return false;
- }
-
- /*--------------------------------------------------------------------------------
- Do things with the man. Keep him safe when shells in the air.
- --------------------------------------------------------------------------------*/
- Boolean doMan(void)
- {
- if (incoming_shells)
- return false;
- if (brainInfo->trees)
- {
- if (brainInfo->man_status || brainInfo->inboat)
- return false;
- if (buildPill())
- return false;
- if (buildRoad())
- return false;
- }
- if (getTrees())
- return false;
- return false;
- }
-
- /*--------------------------------------------------------------------------------
- If we need to then build a road to make thinks go quicker.
- --------------------------------------------------------------------------------*/
- Boolean buildRoad(void)
- {
- TERRAIN mapSpot;
-
- mapSpot = terrainSpot();
- if (mapSpot == RIVER || mapSpot == SWAMP || mapSpot == CRATER
- || mapSpot == RUBBLE || mapSpot == SWAMP)
- {
- if (mapSpot == RIVER || brainInfo->speed < 20)
- {
- brainInfo->build->action = BUILDMODE_ROAD;
- brainInfo->build->x = brainInfo->tankx >> 8;
- brainInfo->build->y = brainInfo->tanky >> 8;
- return true;
- }
- }
- return false;
- }
-
- /*--------------------------------------------------------------------------------
- Build a pill near our base.
- --------------------------------------------------------------------------------*/
- Boolean buildPill(void)
- {
- if (!brainInfo->carriedpills)
- return false;
- if (!(brainInfo->armour <= 2 && incoming_shells)) /* if we are about to die, then build the thing */
- {
- if (!brainInfo->base) /* no base nearby */
- return false;
-
- if (brainInfo->base->info & OBJECT_HOSTILE)
- return false;
-
- if ((rangeFromMe(brainInfo->base) >> 8) > 4)
- return false;
- }
-
- brainInfo->build->action = BUILDMODE_PBOX;
- brainInfo->build->x = brainInfo->tankx >> 8;
- brainInfo->build->y = brainInfo->tanky >> 8;
-
- return true;
- }
-
- /*--------------------------------------------------------------------------------
- If we are getting low on trees, then go get some.
- --------------------------------------------------------------------------------*/
- Boolean getTrees(void)
- {
- long range;
- u_char x, y;
-
- if (brainInfo->trees > 20)
- return false;
-
- if (terrainSpot() == FOREST)
- {
- brainInfo->build->action = BUILDMODE_FARM;
- brainInfo->build->x = brainInfo->tankx >> 8;
- brainInfo->build->y = brainInfo->tanky >> 8;
- return true;
- }
-
- if (findObject(TERRAIN_MASK, FOREST, 6, 128, &x, &y))
- {
- brainInfo->build->action = BUILDMODE_FARM;
- brainInfo->build->x = x;
- brainInfo->build->y = y;
- return true;
- }
- return false;
- }
-
- /*--------------------------------------------------------------------------------
- Tally the shots comming at us.
- --------------------------------------------------------------------------------*/
- void countIncommingShots(void)
- {
- ObjectInfo *ob;
- short n;
- long dx, dy, minDist;
- char dev;
-
- // Count all shells coming towards us.
- incoming_shells = 0;
- minDist = 100000;
- closestShot = nil;
- for (n = 0; n < brainInfo->num_objects; ++n)
- {
- ob = &(brainInfo->objects[n]);
- if (ob->object == OBJECT_SHOT)
- {
- /* dev = difference in the shots direction of travel and our
- direction from the shot */
- dx = (unsigned long)brainInfo->tankx - (unsigned long)ob->x;
- dy = (unsigned long)brainInfo->tanky - (unsigned long)ob->y;
- dev = ob->direction - aim(dx, dy);
- if (dev > -45 && dev < 45)
- {
- ++incoming_shells;
- if (minDist > (dx * dx + dy * dy))
- {
- minDist = dx * dx + dy * dy;
- closestShot = ob;
- }
- }
- }
- }
- }
-
- /*--------------------------------------------------------------------------------
- Avoid the shots comming at us.
- --------------------------------------------------------------------------------*/
- Boolean avoidShots(void)
- {
- if ((incoming_shells > 4 || incoming_shells >= brainInfo->armour) && closestShot)
- {
- obliquelyAvoidSpace(closestShot->x, closestShot->y);
- speedUp();
- return true;
- }
- return false;
- }
-
- /*--------------------------------------------------------------------------------
- If we are suddenly in water, then get out, and avoid it.
- --------------------------------------------------------------------------------*/
- Boolean avoidWater(void)
- {
- if (brainInfo->inboat)
- return false;
- if (terrainSpot() == RIVER)
- {
- /* #### perhaps build bridge here #### */
- if (approachObject(TERRAIN_MASK, ROAD, 4, 30)
- || approachObject(TERRAIN_MASK, FOREST, 4, 30)
- || approachObject(TERRAIN_MASK, GRASS, 4, 30))
- return speedUp();
- }
-
- if (avoidObject(TERRAIN_MASK, RIVER, 2))
- return speedUp();
- return false;
- }
-
- /*--------------------------------------------------------------------------------
- Avoid map square.
- --------------------------------------------------------------------------------*/
- void avoidSpace(WORLD_X x, WORLD_Y y)
- {
- short direction;
-
- direction = aim((unsigned long)x - (unsigned long)brainInfo->tankx,
- (unsigned long)y - (unsigned long)brainInfo->tanky);
-
- if (direction > brainInfo->direction && direction - brainInfo->direction < 128)
- setkey(newKeys, KEY_turnleft);
- else if (direction < 128 && brainInfo->direction > 128 + direction)
- setkey(newKeys, KEY_turnleft);
- else
- setkey(newKeys, KEY_turnright);
- }
-
- /*--------------------------------------------------------------------------------
- Avoid map square at an angle.
- --------------------------------------------------------------------------------*/
- void obliquelyAvoidSpace(WORLD_X x, WORLD_Y y)
- {
- short direction, da;
-
- direction = aim((unsigned long)x - (unsigned long)brainInfo->tankx,
- (unsigned long)y - (unsigned long)brainInfo->tanky);
-
- if (direction > brainInfo->direction)
- da = direction - brainInfo->direction;
- else
- da = brainInfo->direction - direction;
- if (direction > brainInfo->direction && direction - brainInfo->direction < 128)
- {
- if (da < 90)
- setkey(newKeys, KEY_turnleft);
- }
- else if (direction < 128 && brainInfo->direction > 128 + direction)
- {
- if (da < 90)
- setkey(newKeys, KEY_turnleft);
- }
- else
- {
- if (da < 90)
- setkey(newKeys, KEY_turnright);
- }
- }
-
- /*--------------------------------------------------------------------------------
- Approach map square.
- --------------------------------------------------------------------------------*/
- void approachSpace(WORLD_X x, WORLD_Y y)
- {
- short direction;
- char da, max, min;
- u_long *keysToSet;
- long range;
-
- direction = aim((unsigned long)x - (unsigned long)brainInfo->tankx,
- (unsigned long)y - (unsigned long)brainInfo->tanky);
-
- da = brainInfo->direction - direction;
- range = (findrange(x, y, brainInfo->tankx, brainInfo->tanky)) >> 8;
- /* if (range > 8)
- {max = 7; min = 2;}
- else if (range > 4)
- {max = 10; min = 4;}
- else if (range > 2)
- {max = 20; min = 7;}
- else
- {max = 90; min = 45;}*/
-
- /*if (range > 15)
- range = 15;
- max = (15 - range) * 3;
- min = (15 - range);*/
-
- max = 15;
- min = 2;
- if (da < max && da > -max)
- keysToSet = &newTaps;
- else
- keysToSet = &newKeys;
- if (da < min && da > -min)
- return;
- if (direction > brainInfo->direction && direction - brainInfo->direction < 128)
- setkey(*keysToSet, KEY_turnright);
- else if (direction < 128 && brainInfo->direction > 128 + direction)
- setkey(*keysToSet, KEY_turnright);
- else
- setkey(*keysToSet, KEY_turnleft);
- }
-
- /*--------------------------------------------------------------------------------
- If we are damaged, then avoid the pillboxes.
- --------------------------------------------------------------------------------*/
- Boolean avoidPill(void)
- {
- ObjectInfo *ob;
- u_long range;
-
- if (brainInfo->armour >= 4) /* do not avoid if we have armour */
- return false;
-
- for (ob = &brainInfo->objects[0]; ob < &brainInfo->objects[brainInfo->num_objects]; ob++)
- {
- if (ob->object == OBJECT_PILLBOX && (ob->info & OBJECT_HOSTILE))
- {
- if (ob->direction <= 2)
- return false;
- range = rangeFromMe(ob);
- if ((range >> 8) > 8)
- continue;
-
- avoidSpace(ob->x, ob->y);
-
- return speedUp();
- }
- }
- return false;
- }
-
- /*--------------------------------------------------------------------------------
- Avoid enemies
- --------------------------------------------------------------------------------*/
- Boolean avoidEnemy(void)
- {
- }
-
-
- /*--------------------------------------------------------------------------------
- Avoid nearby mines if we are moving, by turning and slowing.
- --------------------------------------------------------------------------------*/
- Boolean avoidMines(void)
- {
- u_char x, y;
- Boolean mine;
-
- if (!brainInfo->speed) /* we are stopped so no need to avoid */
- return false;
-
- mine = findObject(TERRAIN_MINE, TERRAIN_MINE, 2, 10, &x, &y);
- if (!mine)
- if (!findObject(TERRAIN_MINE, TERRAIN_MINE, 1, 50, &x, &y))
- return false;
- avoidSpace(x << 8, y << 8);
- if (brainInfo->speed > MIN_SPEED)
- return slowDown();
- else
- return speedUp();
- }
-
- /*--------------------------------------------------------------------------------
- Avoid going into deep water, and get out of it when dead.
- --------------------------------------------------------------------------------*/
- Boolean avoidDeepWater(void)
- {
- if (terrainSpot() == DEEPSEA)
- {
- /*approachObject(DEEPSEA, 0, 14, 128);*/ /* anything but deepsea */
- if (!approachObject(TERRAIN_MASK, ROAD, 14, 128))
- if (!approachObject(TERRAIN_MASK, GRASS, 14, 128))
- if (!approachObject(TERRAIN_MASK, FOREST, 14, 128))
- if (!approachObject(TERRAIN_MASK, SWAMP, 14, 128))
- if (!approachObject(TERRAIN_MASK, RUBBLE, 14, 128))
- if (!approachObject(TERRAIN_MASK, HALFBUILDING, 14, 128))
- if (!approachObject(TERRAIN_MASK, BUILDING, 14, 128))
- approachObject(TERRAIN_MASK, CRATER, 14, 128);
-
- return speedUp();
- }
-
- if (avoidObject(TERRAIN_MASK, DEEPSEA, 4))
- return slowDown();
-
- return false;
- }
-
-
- /*--------------------------------------------------------------------------------
- Avoid nearby objects if we are moving, by turning away.
- --------------------------------------------------------------------------------*/
- Boolean avoidObject(u_char mask, TERRAIN thing, short distance)
- {
- u_char x, y;
-
- if (!brainInfo->speed)
- return false;
- if (findObject(mask, thing, distance, 45, &x, &y))
- {
- avoidSpace(x << 8, y << 8);
- return true;
- }
- return false; /* no evasion needed */
- }
-
- /*--------------------------------------------------------------------------------
- Turn towards nearby objects.
- --------------------------------------------------------------------------------*/
- Boolean approachObject(u_char mask, TERRAIN thing, short distance, short da)
- {
- u_char x, y;
-
- if (findObject(mask, thing, distance, da, &x, &y))
- {
- approachSpace(x << 8, y << 8);
- return true;
- }
- return false;
- }
-
- /*--------------------------------------------------------------------------------
- Find the thing in the map we can see.
- --------------------------------------------------------------------------------*/
- Boolean findObject(u_char mask, TERRAIN thing, short distance, short da, u_char *x, u_char *y)
- {
- short r;
- BYTE angle;
- WORLD_X wx;
- WORLD_Y wy;
-
- for (r = 1; r <= distance; ++r)
- {
- for (angle = 0; angle <= da; angle += 5)
- {
- wx = brainInfo->tankx + sin(brainInfo->direction + angle) * r;
- wy = brainInfo->tanky - cos(brainInfo->direction + angle) * r;
- if (wx >> 8 == brainInfo->tankx >> 8 && wy >> 8 == brainInfo->tanky >> 8)
- continue;
-
- if ((raw_getmapcell(wx >> 8, wy >> 8) & mask) == thing)
- {
- *x = wx >> 8;
- *y = wy >> 8;
- return true;
- }
- wx = brainInfo->tankx + sin(brainInfo->direction - angle) * r;
- wy = brainInfo->tanky - cos(brainInfo->direction - angle) * r;
- if (wx >> 8 == brainInfo->tankx >> 8 && wy >> 8 == brainInfo->tanky >> 8)
- continue;
-
- if ((raw_getmapcell(wx >> 8, wy >> 8) & mask) == thing)
- {
- *x = wx >> 8;
- *y = wy >> 8;
- return true;
- }
- }
- }
- return false;
- }
-
- /*--------------------------------------------------------------------------------
- Return the terrain info from the map location near us.
- --------------------------------------------------------------------------------*/
- TERRAIN mapNearUs(u_char direction, char distance)
- {
- WORLD_X wx, wy;
-
- wx = brainInfo->tankx + sin(direction) * distance;
- wy = brainInfo->tanky - cos(direction) * distance;
-
- return raw_getmapcell(wx >> 8, wy >> 8);
- }
-
- /*--------------------------------------------------------------------------------
- Return the terrain info from the map.
- --------------------------------------------------------------------------------*/
- TERRAIN raw_getmapcell(MAP_X x, MAP_Y y)
- {
- if (x < brainInfo->view_left || y < brainInfo->view_top)
- return(DEEPSEA);
- y -= brainInfo->view_top;
- x -= brainInfo->view_left;
- if (x >= brainInfo->view_width || y >= brainInfo->view_height)
- return(DEEPSEA);
- return (brainInfo->viewdata[y * brainInfo->view_width + x]);
- }
-
- /*--------------------------------------------------------------------------------
- Send a debug msg to ourselves.
- --------------------------------------------------------------------------------*/
- void sendDebugMsg(short msgIndex, char *theMessage, ...)
- {
- short x;
- char buffer[256];
- va_list ptr;
-
- *(brainInfo->messagedest) = 0xFFFFFFFF;
- if (!brainInfo->sendmessage[0])
- {
- if (TickCount() < lastMsg)
- return;
- if (msgIndex >= MAX_MSGS)
- return;
- if (TickCount() - msgTimes[msgIndex] <= MIN_WAIT)
- return;
- msgTimes[msgIndex] = TickCount();
- lastMsg = TickCount() + 60;
-
- va_start(ptr, theMessage);
- buffer[0] = vsprintf((char *)buffer+1, theMessage, ptr);
-
- for (x = 0; x <= buffer[0]; ++x)
- brainInfo->sendmessage[x] = buffer[x];
- }
- }
-
- /*--------------------------------------------------------------------------------
- Find the distance between two objects
- --------------------------------------------------------------------------------*/
- u_long findrange(long x1, long y1, long x2, long y2)
- {
- long dx, dy;
-
- dx = x1 - x2;
- dy = y1 - y2;
- return (FracSqrt(dx * dx + dy * dy) >> 15);
- }
-
- /*--------------------------------------------------------------------------------
- return a number between min - 1 and max
- --------------------------------------------------------------------------------*/
- unsigned short rnd(short min, short max)
- {
- unsigned short ranNum;
- long range, t;
-
- ranNum = Random();
- range = max - min;
- t = (ranNum * range) / 65536;
- return (t + min);
- }
-
- /*--------------------------------------------------------------------------------
- Slow down.
- --------------------------------------------------------------------------------*/
- Boolean slowDown(void)
- {
- setkey(newKeys, KEY_slower);
- clearkey(newKeys, KEY_faster);
- return true;
- }
-
- /*--------------------------------------------------------------------------------
- Speed up.
- --------------------------------------------------------------------------------*/
- Boolean speedUp(void)
- {
- setkey(newKeys, KEY_faster);
- clearkey(newKeys, KEY_slower);
- return true;
- }
-
- /*--------------------------------------------------------------------------------
- The terrain at the spot.
- --------------------------------------------------------------------------------*/
- TERRAIN terrainSpot(void)
- {
- return raw_getmapcell(brainInfo->tankx >> 8, brainInfo->tanky >> 8) & TERRAIN_MASK;
- }
-
-
-
-
-
-